package com.dake.jdk8.reflect;

import com.dake.jdk8.vo.reflect.Person;
import com.dake.jdk8.vo.reflect.TestReflectSet;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Reflect_01 {

    private static final Logger LOGGER = LoggerFactory.getLogger(Reflect_01.class);

    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//        String s1 = reflectSet("name", "张三");
//        System.out.println(s1);
        System.out.println("-------------方法1--------------");
        reflectSet("name", "张三");
        System.out.println("-------------方法2--------------");
        String s2 = testReflectSet();
        System.out.println(s2);
        System.out.println("-------------方法3--------------");
        Person person = new Person();
        String s3 = "name";
//        setValue(person, s3, Person.class.getDeclaredField(s3).getType(), "汪汪");
//        setValue1(person, s3, "汪汪");
        setValue2(person, s3, "汪汪");
        String name = person.getName();
        System.out.println(name);
        System.out.println("-------------方法4--------------");
        testReflectGet();

        TestReflectSet testReflectSet = new TestReflectSet();
        asignValue2Obj(testReflectSet, "Name", "wangbadan");
        System.out.println(testReflectSet.getName());
    }

    /**
     * 方法1：利用反射，不通过属性的set方法给对象的属性赋值
     *
     * @param param
     * @param name
     * @return
     * @throws NoSuchFieldException
     */
    private static void reflectSet(String param, String name) throws NoSuchFieldException {
        verifyParam(param);

        TestReflectSet testReflectSet = new TestReflectSet();
      /*  Class<? extends TestReflectSet> testReflectSetClass = testReflectSet.getClass();
        Field[] fields = testReflectSetClass.getFields();
        boolean contains = false;
        for (Field field : fields) {
            System.out.println(field.toString());
            if (field.toString().equals(param)) {
                contains = true;
                break;
            }
        }*/

        /*if (!contains) {
            LOGGER.error(String.format("参数【{}】非【{}】类的字段"), param, "TestReflectSet");
        }*/

        Field declaredField = null;
        try {

            declaredField = testReflectSet.getClass().getDeclaredField(param);
//            System.out.println("修改前的值：" + declaredField.get(testReflectSet));
            declaredField.setAccessible(true);
            declaredField.set(testReflectSet, name);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
//        return declaredField.getClass().getField(param).toString();
//        testReflectSet.getClass().getDeclaredField(param);
        String name1 = testReflectSet.getName();
        System.out.println(name1);

//        System.out.println(declaredField.getName());
    }

    /**
     * 方法:2：利用反射，通过调用属性的set方法给对象赋值
     *
     * @return
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    private static String testReflectSet() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        TestReflectSet testReflectSet = new TestReflectSet();
        Method setNameMethod = testReflectSet.getClass().getMethod("setName", String.class);
        String s = "张三";
        setNameMethod.invoke(testReflectSet, s);
        return testReflectSet.getName();
    }

    private static <T> void asignValue2Obj(T t, String filed, String value) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
//        Object o = t.getClass().getDeclaredConstructor().newInstance();
//        Method setNameMethod = o.getClass().getMethod("set" + filed, String.class);
//        setNameMethod.invoke(o, value);
//        Method method = t.getClass().getDeclaredMethod("set" + filed, new Class[]{typeClass});
    }

    /**
     * 方法3：根据属性:拿到set方法，并把值set到对象中
     *
     * @param obj       对象
     * @param typeClass
     * @param value
     */
    public static void setValue(Object obj, String filedName, Class<?> typeClass, Object value) throws NoSuchFieldException {
//        filedName = removeLine(filedName);
        String methodName = "set" + filedName.substring(0, 1).toUpperCase() + filedName.substring(1);
//        Object object = null;
        try {
            Method method = obj.getClass().getDeclaredMethod(methodName, new Class[]{typeClass});
            method.invoke(obj, new Object[]{typeClass.cast(value)});
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static void setValue1(Object obj, String filedName, Object value) throws NoSuchFieldException {
//        filedName = removeLine(filedName);
        String methodName = "set" + filedName.substring(0, 1).toUpperCase() + filedName.substring(1);
//        Object object = null;
        Class<?> type = obj.getClass().getDeclaredField(filedName).getType();
        try {
            Method method = obj.getClass().getDeclaredMethod(methodName,
                    new Class[]{type});
            method.invoke(obj, new Object[]{type.cast(value)});
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static void setValue2(Object obj, String filedName, Object value) throws NoSuchFieldException {
//        filedName = removeLine(filedName);
        String methodName = "set" + filedName.substring(0, 1).toUpperCase() + filedName.substring(1);
//        Object object = null;
        Class<?> type = obj.getClass().getDeclaredField(filedName).getType();
        try {
            Method method = obj.getClass().getDeclaredMethod(methodName,
                    type);
            method.invoke(obj, value);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private static void testReflectGet() throws NoSuchFieldException {
        TestReflectSet testReflectSet = new TestReflectSet();
        testReflectSet.setName("张三");
        Field name = testReflectSet.getClass().getDeclaredField("name");
        name.setAccessible(true);
        String name1 = testReflectSet.getName();
        System.out.println(name1);
    }

    private static void verifyParam(String param) {
        if (StringUtils.isBlank(param)) {
            Assert.notNull(param, "---------参数不可为空---------");
        }
    }

}
